package info.batcloud.fanli.core.service.impl;

import com.ctospace.archit.common.pagination.Paging;
import info.batcloud.fanli.core.dto.SellerPromotionItemDTO;
import info.batcloud.fanli.core.entity.SellerPromotionItem;
import info.batcloud.fanli.core.enums.SellerPromotionItemStatus;
import info.batcloud.fanli.core.helper.PagingHelper;
import info.batcloud.fanli.core.repository.SellerPromotionItemRepository;
import info.batcloud.fanli.core.repository.ShopcatRepository;
import info.batcloud.fanli.core.service.SellerPromotionItemService;
import info.batcloud.fanli.core.service.UserServiceSubscriptionService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.inject.Inject;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import java.util.Date;
import java.util.List;
import java.util.function.Function;

@Service
public class SellerPromotionItemServiceImpl implements SellerPromotionItemService {

    @Inject
    private SellerPromotionItemRepository sellerPromotionItemRepository;

    @Inject
    private UserServiceSubscriptionService userServiceSubscriptionService;

    @Inject
    private ShopcatRepository shopcatRepository;

    @Override
    public void saveSellerPromotionItem(SellerPromotionItemSaveParam param) {
        SellerPromotionItem item = new SellerPromotionItem();
        item.setEcomPlat(param.getEcomPlat());
        item.setPicUrl(param.getPicUrl());
        item.setShopTitle(param.getShopTitle());
        item.setTitle(param.getTitle());
        item.setSourceItemUrl(param.getSourceItemUrl());
        item.setImgList(param.getImgs());
        item.setDayLimitNum(param.getDayLimitNum());
        item.setKeywords(param.getKeywords());
        item.setLogisticsCompany(param.getLogisticsCompany());
        item.setPrice(param.getOriginPrice() - param.getRebateFee());
        //如果用户已经订购了推广的服务，那么这里直接就是审核通过，否则则需要先审核
        if (userServiceSubscriptionService.checkServiceValid(param.getUserId(),
                info.batcloud.fanli.core.enums.Service.PROMOTION_ITEM)) {
            item.setStatus(SellerPromotionItemStatus.WAIT_SALE);
        } else {
            item.setStatus(SellerPromotionItemStatus.WAIT_VERIFY);
        }
        item.setTotalNum(0);
        item.setTotalSaleNum(0);
        item.setUserId(param.getUserId());
        item.setRebateFee(param.getRebateFee());
        item.setOriginPrice(param.getOriginPrice());
        item.setScreenshotList(param.getScreenshotList());
        item.setShopcat(shopcatRepository.findOne(param.getShopcatId()));
        item.setStartTime(param.getStartTime());
        item.setCreateTime(new Date());
        item.setRemainNum(item.getTotalNum() - item.getTotalSaleNum());
        item.setDescription(param.getDescription());
        sellerPromotionItemRepository.save(item);
    }

    @Override
    public void updateSellerPromotionItem(SellerPromotionItemUpdateParam param) {
        SellerPromotionItem item = sellerPromotionItemRepository.findOne(param.getId());
        if (param.getUserId() != null) {
            Assert.isTrue(item.getUserId().equals(param.getUserId()), "");
        }
        item.setShopTitle(param.getShopTitle());
        item.setTitle(param.getTitle());
        item.setDayLimitNum(param.getDayLimitNum());
        item.setKeywords(param.getKeywords());
        item.setLogisticsCompany(param.getLogisticsCompany());
        item.setPrice(param.getOriginPrice() - param.getRebateFee());
        item.setScreenshotList(param.getScreenshotList());
        /**
         * 非常重要，这里只有审核中和审核失败的状态，才可以修改返现金额
         * 否则将会出现错误
         * */
        if (item.getStatus() == SellerPromotionItemStatus.WAIT_VERIFY
                || item.getStatus() == SellerPromotionItemStatus.VERIFY_FAIL
                ) {
            item.setRebateFee(param.getRebateFee());
        }
        item.setOriginPrice(param.getOriginPrice());
        item.setShopcat(shopcatRepository.findOne(param.getShopcatId()));
        item.setStartTime(param.getStartTime());
        item.setUpdateTime(new Date());
        item.setRemainNum(item.getTotalNum() - item.getTotalSaleNum());
        item.setDescription(param.getDescription());
        sellerPromotionItemRepository.save(item);
    }

    @Override
    public void addPromotionNum(long sellerPromotionItemId, int num, float depositAmount) {
        SellerPromotionItem item = sellerPromotionItemRepository.findOne(sellerPromotionItemId);
        item.setTotalNum(item.getTotalNum() + num);
        item.setGuaranteeFee(item.getGuaranteeFee() + depositAmount);
        item.setRemainNum(item.getTotalNum() - item.getTotalSaleNum());
        sellerPromotionItemRepository.save(item);
    }

    @Override
    public Paging<SellerPromotionItemDTO> search(SearchParam param) {
        Specification<SellerPromotionItem> specification = (root, query, cb) -> {
            Predicate predicate = cb.conjunction();
            List<Expression<Boolean>> expressions = predicate.getExpressions();
            if (StringUtils.isNotBlank(param.getKeywords())) {
                expressions.add(cb.like(root.get("title"), "%" + param.getKeywords() + "%"));
            }
            if (param.getStatus() != null) {
                expressions.add(cb.equal(root.get("status"), param.getStatus()));
            } else {
                expressions.add(cb.notEqual(root.get("status"), SellerPromotionItemStatus.DELETED));
            }
            if (param.getShopcatId() != null) {
                expressions.add(cb.equal(root.get("shopcat").get("id"), param.getShopcatId()));
            }
            if (param.getUserId() != null) {
                expressions.add(cb.equal(root.get("userId"), param.getUserId()));
            }
            if (param.getEcomPlat() != null) {
                expressions.add(cb.equal(root.get("ecomPlat"), param.getEcomPlat()));
            }
            if (param.getFilter() != null) {
                switch (param.getFilter()) {
                    case STARTED:
                        expressions.add(cb.lessThanOrEqualTo(root.get("startTime"), new Date()));
                        break;
                    case WILL_START:
                        expressions.add(cb.greaterThanOrEqualTo(root.get("startTime"), new Date()));
                        break;
                    case SALE_OUT:
                        expressions.add(cb.equal(root.get("remainNum"), 0));
                        break;
                }
            }
            return predicate;
        };
        Sort sort;
        if (param.getSort() != null) {
            switch (param.getSort()) {
                case PRICE_ASC:
                    sort = new Sort(Sort.Direction.ASC, "price");
                    break;
                case PRICE_DESC:
                    sort = new Sort(Sort.Direction.DESC, "price");
                    break;
                case HOT:
                    sort = new Sort(Sort.Direction.DESC, "totalSaleNum");
                    break;
                case START_TIME_DESC:
                    sort = new Sort(Sort.Direction.DESC, "startTime");
                    break;
                default:
                    sort = new Sort(Sort.Direction.DESC, "id");
            }
        } else {
            sort = new Sort(Sort.Direction.DESC, "id");
        }
        Pageable pageable = new PageRequest(param.getPage() - 1,
                param.getPageSize(), sort);
        Page<SellerPromotionItem> page = sellerPromotionItemRepository.findAll(specification, pageable);
        return PagingHelper.of(page, item -> toSellerPromotionItemBO(item), param.getPage(), param.getPageSize());
    }

    @Override
    public SellerPromotionItemDTO findById(long id) {
        SellerPromotionItem item = sellerPromotionItemRepository.findOne(id);
        return toSellerPromotionItemBO(item);
    }

    @Override
    public void deleteById(long id, Function<Long, Boolean> check) {
        SellerPromotionItem item = sellerPromotionItemRepository.findOne(id);
        if(check != null && !check.apply(item.getUserId())) {
            throw new RuntimeException("");
        }
        item.setStatus(SellerPromotionItemStatus.DELETED);
        sellerPromotionItemRepository.save(item);
    }

    @Override
    public void delistById(long id, Function<Long, Boolean> check) {
        SellerPromotionItem item = sellerPromotionItemRepository.findOne(id);
        if(check != null && !check.apply(item.getUserId())) {
            throw new RuntimeException("");
        }
        item.setDelistTime(new Date());
        item.setStatus(SellerPromotionItemStatus.INSTOCK);
        sellerPromotionItemRepository.save(item);
    }

    @Override
    public void listById(long id, Function<Long, Boolean> check) {
        SellerPromotionItem item = sellerPromotionItemRepository.findOne(id);
        if(check != null && !check.apply(item.getUserId())) {
            throw new RuntimeException("");
        }
        item.setListTime(new Date());
        item.setStatus(SellerPromotionItemStatus.ONSALE);
        sellerPromotionItemRepository.save(item);
    }

    private SellerPromotionItemDTO toSellerPromotionItemBO(SellerPromotionItem item) {
        SellerPromotionItemDTO bo = new SellerPromotionItemDTO();
        BeanUtils.copyProperties(item, bo);
        bo.setRemainSeconds((bo.getStartTime().getTime() - System.currentTimeMillis()) / 1000);
        return bo;
    }

    @Override
    public void verify(long id, VerifyParam param) {
        SellerPromotionItem item = sellerPromotionItemRepository.findOne(id);
        if(param.isSuccess()) {
            item.setStatus(SellerPromotionItemStatus.WAIT_SALE);
        } else {
            item.setStatus(SellerPromotionItemStatus.VERIFY_FAIL);
        }
        sellerPromotionItemRepository.save(item);
    }
}
